﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WSManager.Model;
using StringVariables;

namespace WSManager.Wpf.Dialogs
{
    /// <summary>
    /// Interaction logic for EditVariables.xaml
    /// </summary>
    partial class EditVariables : Window
    {
        internal IDictionary<string, string> Variables { get; set; }

        private IEnumerable<VariableDefinition> _definitions;

        internal IEnumerable<VariableDefinition> Definitions
        {
            get { return _definitions; }
            set
            {
                _definitions = value;
                Redraw();
            }
        }

        internal Action<IDictionary<string, string>> SaveCallback { get; set; }

        public EditVariables()
        {
            InitializeComponent();
        }

        void Redraw()
        {
            variablesGrid.Children.Clear();
            variablesGrid.RowDefinitions.Clear();
            foreach (var definition in Definitions)
            {
                var row = AddVariableRow();
                AddLabel(definition, row);
                AddControl(definition, row);
            }
        }

        int AddVariableRow()
        {
            var row = new RowDefinition();
            row.Height = GridLength.Auto;
            variablesGrid.RowDefinitions.Add(row);
            return variablesGrid.RowDefinitions.Count - 1;
        }

        void AddLabel(VariableDefinition def, int row)
        {
            var tb = new TextBlock();
            tb.Text = def.Name;
            Grid.SetColumn(tb, 0);
            Grid.SetRow(tb, row);
            variablesGrid.Children.Add(tb);
        }

        void AddControl(VariableDefinition def, int row)
        {
            var control = CreateControl(def);
            Grid.SetRow(control, row);
            Grid.SetColumn(control, 1);
            variablesGrid.Children.Add(control);
        }

        FrameworkElement CreateControl(VariableDefinition def)
        {
            FrameworkElement control;
            if (def.GetType() == typeof(BoolVariableType))
            {
                var c = new CheckBox();
                if (Variables.ContainsKey(def.Name) || !string.IsNullOrEmpty(def.DefaultValue))
                {
                    bool isChecked;
                    if ((Variables.ContainsKey(def.Name) && bool.TryParse(Variables[def.Name], out isChecked)) || bool.TryParse(def.DefaultValue, out isChecked))
                    {
                        c.IsChecked = isChecked;
                    }
                }
                c.Checked += (s, e) =>
                {
                    ValueChanged(s, bool.TrueString, def);
                };
                c.Unchecked += (s, e) =>
                {
                    ValueChanged(s, bool.FalseString, def);
                };
                control = c;
            }
            else
            {
                var c = new TextBox();
                if (Variables.ContainsKey(def.Name))
                {
                    c.Text = Variables[def.Name];
                }
                else
                {
                    c.Text = def.DefaultValue;
                }
                c.TextChanged += (s, e) =>
                {
                    ValueChanged(s, (s as TextBox).Text, def);
                };
                control = c;
            }
            //else if (def.Type.GetType() == typeof(StringVariableType))
            //{
            //    var c = new TextBox();
            //    if (Variables.ContainsKey(def.Name))
            //    {
            //        c.Text = Variables[def.Name];
            //    }
            //    else if (!string.IsNullOrEmpty(def.DefaultValue))
            //        c.Text = def.DefaultValue;
            //    c.TextChanged += (s, e) =>
            //    {
            //        ValueChanged(s, (s as TextBox).Text, def);
            //    };
            //    control = c;
            //}
            //else if (def.Type.GetType() == typeof(IntVariableType))
            //{
            //    var c = new TextBox();
            //    if (Variables.ContainsKey(def.Name))
            //    {
            //        int val;
            //        if (int.TryParse(Variables[def.Name], out val))
            //            c.Text = val;
            //    }
            //    else if (!string.IsNullOrEmpty(def.DefaultValue))
            //    {
            //        int val;
            //        if(int.TryParse(def.DefaultValue), val)
            //            c.Text=val;
            //    }
            //    c.TextChanged += (s, e) =>
            //    {
            //        ValueChanged(s, (s as TextBox).Text, def);
            //    };
            //    control = c;
            //}
            //else if (def.Type.GetType() == typeof(RealVariableType))
            //{
            //    var c = new TextBox();
            //    if (Variables.ContainsKey(def.Name))
            //    {
            //        double val;
            //        if (double.TryParse(Variables[def.Name], out val))
            //            c.Text = Variables[def.Name];
            //    }
            //    c.TextChanged += (s, e) =>
            //    {
            //        ValueChanged(s, (s as TextBox).Text, def);
            //    };
            //    control = c;
            //}
            return control;
        }

        void ValueChanged(object sender, string newValue, VariableDefinition def)
        {
            var s = sender as FrameworkElement;
            if (!Variables.ContainsKey(def.Name))
            {
                Variables.Add(def.Name, newValue);
            }
            else Variables[def.Name] = newValue;
            if (IsValid(newValue, def))
            {

            }
            else
            {

            }
        }

        bool IsValid(string value, VariableDefinition def)
        {
            if(!string.IsNullOrEmpty(value) || string.IsNullOrEmpty(def.DefaultValue))
                return def.Type.IsValid(value);
            return true;
        }

        bool IsValid(VariableDefinition def)
        {
            return IsValid(Variables.ValueOrDefault(def.Name), def);
        }

        private void Save()
        {
            var invalids = Definitions.Where(def => !IsValid(def)); 
            if (invalids.GetEnumerator().MoveNext())
            {
                //there are some invalids
                MessageBox.Show(String.Format("Can not save - some fields are invalid: {0}", String.Join(", ", invalids.Select(d => d.Name).ToArray())), "Variables Editor");
            }
            else
            {
                Close();
                SaveCallback(Variables);
            }
        }

        #region uiEvents
        private void Save_Click(object sender, RoutedEventArgs e)
        {
            Save();
        }
        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        #endregion
    }

    public class EditVariablesDialog
    {
        EditVariables _window;

        public static EditVariablesDialog Show(IEnumerable<VariableDefinition> definitions, IDictionary<string, string> variables, Action<IDictionary<string, string>> saveCallback)
        {
            if (definitions == null) throw new ArgumentNullException("definitions");
            var d = new EditVariablesDialog();
            d._window = new EditVariables();
            d._window.Variables = variables;
            d._window.Definitions = definitions;
            d._window.SaveCallback = saveCallback;
            d._window.Show();
            return d;
        }

        public static EditVariablesDialog Show(IEnumerable<VariableDefinition> definitions, IDictionary<string, string> variables)
        {
            return Show(definitions, variables, s => { });
        }

        public static EditVariablesDialog Show(IEnumerable<VariableDefinition> definitions, Action<IDictionary<string, string>> saveCallback)
        {
            return Show(definitions, new Dictionary<string, string>(), saveCallback);
        }

    }
}
